package com.zyg.cod.service;

import com.alibaba.fastjson.JSONObject;
import com.zyg.cod.util.Base64Util;
import com.zyg.cod.util.Document2MapUtil;
import com.zyg.cod.util.WriteFileUtil;
import org.apache.log4j.Logger;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 加密服务
 * 将企业ERP的业务报文的内容加密后放到一个含有传输头TransInfo的报文里，通过第三方通道传向省市单一窗口
 */
public class EncryptXmlService {
    private static Logger log=Logger.getLogger(EncryptXmlService.class);

    private static final SimpleDateFormat ymdhms = new SimpleDateFormat("yyyyMMddHHmmss");
    private static SAXReader saxReader = new SAXReader();
    private static String beforeEncryptPath;//未加密前的业务报文路径
    private static String afterEncryptPath;//加密后的传输报文路径
    public EncryptXmlService(String beforeEncryptPath,String afterEncryptPath){
        super();
        this.beforeEncryptPath=beforeEncryptPath;
        this.afterEncryptPath=afterEncryptPath;
    }

    /**
     * 加密
     */
    public static void doEncrypt() {
        List<File> rightFileList=new ArrayList<>();
        List<File> errorFileList=new ArrayList<>();
        //1.读取指定路径下的所有业务报文文件
        List<File> fileList = WriteFileUtil.getFilesByPath(beforeEncryptPath);//不递归文件夹，只取.xml文件
        for (File file : fileList) {
            try{
                String fileName = file.getName();
                //2.将原xml内容转为String并加密
                String xmlStr = WriteFileUtil.file2String(file);
                //加密方法
                String afterEncryptXmlStr = Base64Util.encodeString(xmlStr);
                //3.解析原xml内容为map
                Map<String,String> headMap=getHeadMap(file);
                //4.组装含有transinfo传输头的报文
                String composeAfterXmlStr = composeReceiptXml(headMap, afterEncryptXmlStr, fileName);
                //5.将组装后的报文写出到指定目录
                WriteFileUtil.writeString2File(afterEncryptPath, fileName, composeAfterXmlStr);
                rightFileList.add(file);
                log.info(fileName+"报文组装发往"+afterEncryptPath+"成功！");
            }catch (Exception e){
                e.printStackTrace();
                //不抛出异常，不影响其余文件的操作
                errorFileList.add(file);
            }
        }//for
        if(rightFileList.size()>0){
            CommonService.movedeleteFile(rightFileList,true);
        }
        if(errorFileList.size()>0){
            CommonService.movedeleteFile(errorFileList,false);
        }
    }

    /**
     * 组装发往企业ERP的回执报文String内容
     */
    public static String composeReceiptXml(Map<String, String> headMap, String encodeAfterXmlStr, String receiptXmlFileName) {
        String composeXmlStr = "";
        //按照湖北省电子口岸的第三方传输通道要求的回执报文格式进行组装
        String messageType = headMap.get("messageType");//报文类型
        String tradeCode = headMap.get("tradeCode");//企业统一编码
        String guid = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();//32位GUID
        //开始组装
        StringBuilder xmlContentSB = new StringBuilder("");
        xmlContentSB
                .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
                .append("<DxpMsg xmlns=\"http://www.chinaport.gov.cn/dxp\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ver=\"1.0\">\n")
                .append("<TransInfo>\n")
                .append("<CopMsgId>").append(guid).append("</CopMsgId>\n")
                .append("<SenderId>").append(tradeCode).append("</SenderId>\n")
                .append("<ReceiverIds><ReceiverId>").append(messageType).append("</ReceiverId></ReceiverIds>\n")
                .append("<CreatTime>").append(ymdhms.format(new Date())).append("</CreatTime>\n")
                .append("<MsgType>").append(messageType).append("</MsgType>\n")
                .append("</TransInfo>\n")
                .append("<Data>").append(encodeAfterXmlStr).append("</Data>\n")
                .append("<AddInfo>\n")
                .append("<FileName>").append(receiptXmlFileName).append("</FileName>\n")
                .append("<IcCard>").append("</IcCard>\n")
                .append("</AddInfo>\n")
                .append("</DxpMsg>\n");
        composeXmlStr = xmlContentSB.toString();
        return composeXmlStr;
    }

    /**
     * 获得报文头map
     */
    public static Map<String, String> getHeadMap(File file) {
        Map<String, String> headMap = new HashMap<>();
        JSONObject jsonObject = new JSONObject();
        //开始解析
        FileInputStream fis = null;
        try{
            fis = new FileInputStream(file);
            Document document = saxReader.read(fis);
            Element root = document.getRootElement();
            Document2MapUtil.iterateNodes(root, jsonObject);//将xml文件节点及内容转换为json
            JSONObject jsonBody = (JSONObject) jsonObject.get(root.getName());
            net.sf.json.JSONObject jsonHead = net.sf.json.JSONObject.fromObject(jsonBody.get("head"));
            if (jsonHead == null) {
                throw new RuntimeException(file.getName() + "报文格式不符合规范，没有报文头head！");
            }
            headMap = jsonHead;
        }catch (Exception e){
            throw new RuntimeException(e);
        }finally {
            IOUtils.closeQuietly(fis);
        }
        return headMap;
    }
}
